//!
/**
 ***********************************************************************************************************
 * <RBD3D11HardwareBufferManager Implementation>
 ***********************************************************************************************************
 * @file RBD3D11HardwareBufferManager.cpp
 ***********************************************************************************************************/

/***********************************************************************************************************
 * Precompiled Header
 ***********************************************************************************************************/

/***********************************************************************************************************
 * Includes
 ***********************************************************************************************************/
#include "RBD3D11HardwareBufferManager.h"

#include "RBD3D11Renderer.h"

#include <d3d11.h>
#include <d3dx11.h>

#include "Effects11/Inc/d3dx11effect.h"

#include "RBMain/RBMaterial.h"
#include "RBMain/RBTexture.h"
#include "RBMain/RBTextureSampler.h"
#include "RBMain/RBVertexBuffer.h"
#include "RBMain/RBVertexElement.h"
#include "RBMain/RBIndexBuffer.h"
#include "RBMain/RBVertexDeclaration.h"
#include "RBMain/RBPixelBuffer.h"

#include "RBRenderProcess/RBBlendState.h"
#include "RBRenderProcess/RBDepthStencilState.h"
#include "RBRenderProcess/RBDepthStencilView.h"
#include "RBRenderProcess/RBEffect.h"
#include "RBRenderProcess/RBEffectFactory.h"
#include "RBRenderProcess/RBEffectTechnique.h"
#include "RBRenderProcess/RBEffectPass.h"
#include "RBRenderProcess/RBShaderResourceView.h"
#include "RBRenderProcess/RBRasterizerState.h"
#include "RBRenderProcess/RBRenderTargetView.h"

#include "RBD3D11Mappings.h"

/***********************************************************************************************************
 * Defines
 ***********************************************************************************************************/

/***********************************************************************************************************
 * Classes implementation
 ***********************************************************************************************************/

/**
 ***********************************************************************************************************
 * Constructor
 ***********************************************************************************************************/
RBD3D11HardwareBufferManager::RBD3D11HardwareBufferManager(ID3D11Device* pDevice)
: m_pDevice(pDevice)
{
}

/**
 ***********************************************************************************************************
 * Destructor
 ***********************************************************************************************************/
RBD3D11HardwareBufferManager::~RBD3D11HardwareBufferManager()
{
}

bool RBD3D11HardwareBufferManager::create_buffer( ID3D11Device* dev, ID3D11Buffer** ppBuffer, D3D11_BUFFER_DESC* BufferDesc, void* data )
{
    D3D11_SUBRESOURCE_DATA d3dInitData;
    d3dInitData.pSysMem = data;
    d3dInitData.SysMemPitch = 0;
    d3dInitData.SysMemSlicePitch = 0;

    if (FAILED(dev->CreateBuffer(BufferDesc, &d3dInitData, ppBuffer)))
    {
        return false;
    }
    
    return true;
}


static inline HRESULT CreateD3DBuffer(ID3D11Device* pDevice, uint32 uiBufferSize, uint32 uiStride, uint32 uiUsage, D3D11_BIND_FLAG d3dBindflags, const void* pInitData, ID3D11Buffer** ppD3DBuffer)
{
    D3D11_BUFFER_DESC d3dVertexDesc = 
    {
        uiBufferSize,
        (uiUsage & rb_hw_buffer_usage::HBU_CPUWRITE) ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT,
        d3dBindflags,
        (uiUsage & rb_hw_buffer_usage::HBU_CPUWRITE) ? D3D11_CPU_ACCESS_WRITE : 0,
        0,
        uiStride
    };

    D3D11_SUBRESOURCE_DATA d3dInitData =
    {
        pInitData,
        0,
        0
    };

    return pDevice->CreateBuffer(&d3dVertexDesc, &d3dInitData, ppD3DBuffer);
}


/**************************************************************************************************************************************************************
 * 
 **************************************************************************************************************************************************************/
RBVertexBuffer* RBD3D11HardwareBufferManager::create_vb_from_d3d( ID3D11Buffer* d3d_vb )
{
    D3D11_BUFFER_DESC vb_desc;
    d3d_vb->GetDesc(&vb_desc);

    uint32 vertex_size = vb_desc.StructureByteStride;
    uint32 vertex_count = vb_desc.ByteWidth / vb_desc.StructureByteStride;

    return new RBVertexBuffer(rb_hw_buffer_usage::HBU_DEFAULT, rb_hw_buffer_usage::MP_GPU ,this, vertex_size, vertex_count, d3d_vb);
}



/**************************************************************************************************************************************************************
 * 
 **************************************************************************************************************************************************************/
RBVertexBuffer* RBD3D11HardwareBufferManager::CreateVertexBuffer(uint32 uiUsage, uint32 uiVertexSize, uint32 uiVertexCount, const void* pInitData)
{
    ID3D11Buffer* pD3DVertexBuffer;
    RBVertexBuffer* pVertexBuffer = NULL; 
    uint32 uiBufferSize = uiVertexCount * uiVertexSize;
    uint32 uiStride = uiVertexSize;
    if (SUCCEEDED(CreateD3DBuffer(m_pDevice, uiBufferSize, uiStride, uiUsage, D3D11_BIND_VERTEX_BUFFER, pInitData, &pD3DVertexBuffer)))
    {
        pVertexBuffer = new RBVertexBuffer(uiUsage, rb_hw_buffer_usage::MP_GPU ,this, uiVertexSize, uiVertexCount, pD3DVertexBuffer);
    }
    
    return pVertexBuffer;
}

/**************************************************************************************************************************************************************
 * 
 **************************************************************************************************************************************************************/
RBIndexBuffer* RBD3D11HardwareBufferManager::create_ib_from_d3d( ID3D11Buffer* d3d_vb )
{

}


/**************************************************************************************************************************************************************
 * 
 **************************************************************************************************************************************************************/
RBIndexBuffer* RBD3D11HardwareBufferManager::CreateIndexBuffer(uint32 uiUsage, RBIndexBufferType::EType eIndexType, uint32 uiIndexCount, const void* pInitData)
{
    ID3D11Buffer* pD3DIndexBuffer;
    RBIndexBuffer* pIndexBuffer = NULL;
    uint32 uiStride = (eIndexType == RBIndexBufferType::IT_16BIT) ? 2 : 4;
    uint32 uiBufferSize = uiIndexCount * uiStride;
    if (SUCCEEDED(CreateD3DBuffer(m_pDevice, uiBufferSize, uiStride, uiUsage, D3D11_BIND_INDEX_BUFFER, pInitData, &pD3DIndexBuffer)))
    {
        pIndexBuffer = new RBIndexBuffer(uiUsage, rb_hw_buffer_usage::MP_GPU, this, eIndexType, uiIndexCount, pD3DIndexBuffer);
    }

    return pIndexBuffer;
}

#define MAX_ELEMENTS 8

/**************************************************************************************************************************************************************
 * 
 **************************************************************************************************************************************************************/
RBVertexDeclaration* RBD3D11HardwareBufferManager::CreateVertexDeclaration(RBVertexElement* pElements, uint32 uiElementCount, RBEffectPass* pEffectPass)
{
    D3D11_INPUT_ELEMENT_DESC desc[MAX_ELEMENTS];
    BYTE aStreamUsageIndex[RBVertexElement::MaxStreamCount][RBVertexElement::VEU_COUNT] = {0};
    uint32 aStreamOffset[RBVertexElement::MaxStreamCount] = {0};
    for (uint32 ui=0; ui < uiElementCount; ++ui)
    {
        desc[ui].SemanticName = RBVertexElement::GetUsageName(pElements[ui].Usage);
        desc[ui].SemanticIndex = aStreamUsageIndex[pElements[ui].Stream][pElements[ui].Usage]++;
        desc[ui].Format = RBD3D11Mappings::GetD3D11Format(pElements[ui].Type);
        desc[ui].InputSlot = pElements[ui].Stream;
        desc[ui].AlignedByteOffset = aStreamOffset[pElements[ui].Stream];
        desc[ui].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
        desc[ui].InstanceDataStepRate  = 0;

        aStreamOffset[pElements[ui].Stream] += pElements[ui].GetSize();
    }

    if (pEffectPass == NULL)
    {
        RBEffect* pEffect = RBEffectFactory::GetSingleton()->RetrieveEffect("test");
        pEffectPass = pEffect->GetTechnique(0)->GetPass(0);
    }

    RBVertexDeclaration* pVertexDeclaration = NULL;
    ID3D11InputLayout* pD3DInputLayout = NULL;
    if (SUCCEEDED(m_pDevice->CreateInputLayout(desc, uiElementCount, pEffectPass->GetIASignature(), pEffectPass->GetIASignatureSize(), &pD3DInputLayout)))
    {
        pVertexDeclaration = new RBVertexDeclaration(this, pElements, uiElementCount, pD3DInputLayout);
    }
     
    return pVertexDeclaration;
}
#pragma warning(push)
#pragma warning(disable: 4100)

/**************************************************************************************************************************************************************
 * 
 **************************************************************************************************************************************************************/
RBTexture* RBD3D11HardwareBufferManager::CreateTexture(const char* pcFilename, uint32 uiUsage)
{
    ID3D11Resource* pD3DResource;
    HRESULT hr;
    D3DX11_IMAGE_LOAD_INFO d3dLoadInfo;
    {
        d3dLoadInfo.Width = D3DX11_DEFAULT;
        d3dLoadInfo.Height = D3DX11_DEFAULT;
        d3dLoadInfo.Depth = D3DX11_DEFAULT;
        d3dLoadInfo.FirstMipLevel = D3DX11_DEFAULT;
        d3dLoadInfo.MipLevels = D3DX11_DEFAULT;
        d3dLoadInfo.Usage = RBD3D11Mappings::get_d3d_usage(uiUsage);
        d3dLoadInfo.BindFlags = (d3dLoadInfo.Usage == D3D11_USAGE_STAGING) ? 0 : D3DX11_DEFAULT;
        d3dLoadInfo.CpuAccessFlags = RBD3D11Mappings::get_d3d_cpu_access_flags(uiUsage);
        d3dLoadInfo.MiscFlags = D3DX11_DEFAULT;
        d3dLoadInfo.Format = DXGI_FORMAT_FROM_FILE;
        d3dLoadInfo.Filter = D3DX11_DEFAULT;
        d3dLoadInfo.MipFilter = D3DX11_DEFAULT;
        d3dLoadInfo.pSrcInfo = NULL;

    }

    hr =  D3DX11CreateTextureFromFileA(m_pDevice, pcFilename, &d3dLoadInfo, NULL, &pD3DResource, NULL);
    if (FAILED(hr))
    {
        return NULL;
    }

    D3D11_RESOURCE_DIMENSION resDim;
    pD3DResource->GetType(&resDim);

    switch (resDim)
    {
    case D3D11_RESOURCE_DIMENSION_UNKNOWN: 
    case D3D11_RESOURCE_DIMENSION_TEXTURE1D:
    case D3D11_RESOURCE_DIMENSION_TEXTURE3D:
    case D3D11_RESOURCE_DIMENSION_BUFFER: pD3DResource->Release(); return NULL;
    default: break;
    }

    ID3D11Texture2D* pD3DTexture = (ID3D11Texture2D*)pD3DResource;
    D3D11_TEXTURE2D_DESC d3dTexDesc;
    pD3DTexture->GetDesc(&d3dTexDesc);

    return new RBTexture(RBD3D11Mappings::get_d3d_usage(uiUsage), rb_hw_buffer_usage::MP_GPU, this, pD3DTexture, 
                         RBD3D11Mappings::GetRBPixelFormat(d3dTexDesc.Format), RBTextureType::SURFACE, d3dTexDesc.Width, d3dTexDesc.Height,
                         d3dTexDesc.MipLevels, 1, 1);

}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
RBTexture* RBD3D11HardwareBufferManager::CreateTexture(uint32 uiUsage, uint32 uiWidth, uint32 uiHeight, RBPixelFormat eFormat, 
                                                       RBTextureType::EType eType, uint32 uiMips, uint32 uiDepth, uint32 eMemPool)
{
	UINT d3d_cpu_access_flags=0;
	if (uiUsage & rb_hw_buffer_usage::HBU_CPUREAD) d3d_cpu_access_flags |= D3D11_CPU_ACCESS_READ;
	if (uiUsage & rb_hw_buffer_usage::HBU_CPUWRITE) d3d_cpu_access_flags |= D3D11_CPU_ACCESS_WRITE;
	

    D3D11_TEXTURE2D_DESC d3dDesc = 
    {
        ( int) uiWidth,                                 // UINT Width;
        ( int) uiHeight,                                // UINT Height;
        uiMips,                                         // UINT MipLevels;
        eType == RBTextureType::CUBE ? 6 : 1,           // UINT ArraySize;
        RBD3D11Mappings::GetD3D11PixelFormat(eFormat),  // DXGI_FORMAT Format;
        { 1, 0, },                                      // DXGI_SAMPLE_DESC SampleDesc;
        RBD3D11Mappings::get_d3d_usage(uiUsage),		// D3D11_USAGE Usage;
        RBD3D11Mappings::GetD3D11BindFlags(uiUsage),    // UINT BindFlags;
        RBD3D11Mappings::get_d3d_cpu_access_flags(uiUsage), // UINT CPUAccessFlags;
        RBD3D11Mappings::get_d3d_misc_flags(uiUsage, eType),   // UINT MiscFlags;
    };

    ID3D11Texture2D* pD3DTexture = NULL;
    if (FAILED(m_pDevice->CreateTexture2D(&d3dDesc, NULL, &pD3DTexture )))
    {
        return NULL;
    }
    
    return new RBTexture(uiUsage, eMemPool, this, pD3DTexture, eFormat, eType, uiWidth, uiHeight, uiMips, 1, 1);
}
#pragma warning(pop)

/***********************************************************************************************************
 *
 ***********************************************************************************************************/
RBTexture* RBD3D11HardwareBufferManager::CreateRenderTarget(uint32 uiUsage, uint32 uiWidth, uint32 uiHeight, RBPixelFormat eFormat, 
                                                            uint32 /*uiMSAA*/)
{
    D3D11_TEXTURE2D_DESC d3dDesc = 
    {
        ( int) uiWidth,                 // UINT Width;
        ( int) uiHeight,                // UINT Height;
        1,                              // UINT MipLevels;
        1,                              // UINT ArraySize;
        RBD3D11Mappings::GetD3D11PixelFormat(eFormat),   // DXGI_FORMAT Format;
        { 1, 0, },                      // DXGI_SAMPLE_DESC SampleDesc;
        D3D11_USAGE_DEFAULT,            // D3D11_USAGE Usage;
        RBD3D11Mappings::GetD3D11BindFlags(uiUsage),     // UINT BindFlags;
        0,                              // UINT CPUAccessFlags;
        RBD3D11Mappings::get_d3d_misc_flags(uiUsage, RBTextureType::SURFACE),                              // UINT MiscFlags;
    };

    ID3D11Texture2D* pD3DTexture = NULL;
    if (FAILED(m_pDevice->CreateTexture2D(&d3dDesc, NULL, &pD3DTexture )))
    {
        return NULL;
    }

    return new RBTexture(uiUsage, rb_hw_buffer_usage::MP_GPU, this, pD3DTexture, eFormat, RBTextureType::SURFACE, uiWidth, uiHeight, 1, 1, 1);
}

/***********************************************************************************************************
 *
 ***********************************************************************************************************/
void RBD3D11HardwareBufferManager::OnReset(bool bBeforeReset)
{
    for (std::list<RBHardwareBuffer*>::iterator iterBuffer = m_aAllocatedBuffers.begin(); iterBuffer != m_aAllocatedBuffers.end(); ++iterBuffer)
    {
        (*iterBuffer)->OnReset(bBeforeReset);
    }
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
RBShaderResourceView* RBD3D11HardwareBufferManager::CreateShaderResourceView( RBTexture* pBuffer, RBPixelFormat eFormat )
{
    void* pNative = 0;
    D3D11_SHADER_RESOURCE_VIEW_DESC desc;
    desc.Format = RBD3D11Mappings::GetD3D11PixelFormat((eFormat == PF_UNKNOWN) ? pBuffer->GetFormat(): eFormat);
    
    switch (pBuffer->GetType())
    {
    case RBTextureType::CUBE:
        desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
        desc.TextureCube.MipLevels = pBuffer->GetMipCount();
        desc.TextureCube.MostDetailedMip = 0;
        break;
    default:
        desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
        desc.Texture2D.MipLevels = pBuffer->GetMipCount();
        desc.Texture2D.MostDetailedMip = 0;
        break;
    }


    if (FAILED(m_pDevice->CreateShaderResourceView((ID3D11Resource*)pBuffer->GetNative(), &desc, (ID3D11ShaderResourceView**)&pNative)))
    {
        return NULL;
    }
    return new RBShaderResourceView(pNative, pBuffer);
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
RBRenderTargetView* RBD3D11HardwareBufferManager::CreateRenderTargetView( RBTexture* pBuffer, RBPixelFormat eFormat )
{
    D3D11_RENDER_TARGET_VIEW_DESC desc;
    desc.Format = RBD3D11Mappings::GetD3D11PixelFormat((eFormat == PF_UNKNOWN) ? pBuffer->GetFormat(): eFormat);
    desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
    desc.Texture2D.MipSlice = 0;
    void* pNative;
    if (FAILED(m_pDevice->CreateRenderTargetView((ID3D11Resource*)pBuffer->GetNative(), &desc, (ID3D11RenderTargetView**)&pNative)))
    {
        return NULL;
    }
    return new RBRenderTargetView(pNative, pBuffer);

}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
RBDepthStencilView* RBD3D11HardwareBufferManager::CreateDepthStencilView( RBTexture* pBuffer, RBPixelFormat eFormat )
{
    D3D11_DEPTH_STENCIL_VIEW_DESC desc = 
    {
        RBD3D11Mappings::GetD3D11PixelFormat((eFormat == PF_UNKNOWN) ? pBuffer->GetFormat(): eFormat),
        D3D11_DSV_DIMENSION_TEXTURE2D,
        0
    };
    void* pNative;

    if (FAILED(m_pDevice->CreateDepthStencilView((ID3D11Resource*)pBuffer->GetNative(), &desc, (ID3D11DepthStencilView**)&pNative)))
    {
        return NULL;
    }

    return new RBDepthStencilView(pNative, pBuffer);
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
void RBD3D11HardwareBufferManager::ReleaseNative( RBHardwareBuffer* pHB )
{
    RBCommon::SafeRelease((IUnknown*)pHB->GetNative());
}

static inline D3D11_FILTER ComputeD3DFiler(const RBTextureSampler& sampler)
{
    switch (sampler.MinFilter)
    {
    case RBSamplerState::SFM_POINT:
        {
            switch (sampler.MagFilter)
            {
            case RBSamplerState::SFM_POINT:
                return (sampler.MipFilter == RBSamplerState::SFM_POINT) ? D3D11_FILTER_MIN_MAG_MIP_POINT : D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR;
            case RBSamplerState::SFM_LINEAR:
                return (sampler.MipFilter == RBSamplerState::SFM_POINT) ? D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT : D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR;
            default:
                break;
            }
        }
        break;
    case RBSamplerState::SFM_LINEAR:
        {
            switch (sampler.MagFilter)
            {
            case RBSamplerState::SFM_POINT:
                return (sampler.MipFilter == RBSamplerState::SFM_POINT) ? D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT : D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
            case RBSamplerState::SFM_LINEAR:
                return (sampler.MipFilter == RBSamplerState::SFM_POINT) ? D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT : D3D11_FILTER_MIN_MAG_MIP_LINEAR;
            default:
                break;
            }

        }
        break;
    default:
        break;
    }
    // Don't care about aniso for now
    return D3D11_FILTER_MIN_MAG_MIP_LINEAR;
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
static inline D3D11_TEXTURE_ADDRESS_MODE ComputeD3DAdressMode( const RBSamplerState::AdressMode& adressMode )
{
    switch (adressMode)
    {
    case RBSamplerState::SAM_WRAP:
        return D3D11_TEXTURE_ADDRESS_WRAP;
    case RBSamplerState::SAM_MIRROR:
        return D3D11_TEXTURE_ADDRESS_MIRROR;
    case RBSamplerState::SAM_CLAMP:
        return D3D11_TEXTURE_ADDRESS_CLAMP;
    case RBSamplerState::SAM_BORDER:
        return D3D11_TEXTURE_ADDRESS_BORDER;
    default:
        return D3D11_TEXTURE_ADDRESS_WRAP;
    }
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
RBShaderSamplerState* RBD3D11HardwareBufferManager::CreateSamplerState( const RBTextureSampler& sampler )
{
    ID3D11SamplerState* pState;
    D3D11_SAMPLER_DESC desc = 
    {
        ComputeD3DFiler(sampler),
        ComputeD3DAdressMode(sampler.U),
        ComputeD3DAdressMode(sampler.V),
        ComputeD3DAdressMode(sampler.W),
        0.0f,
        16,
        D3D11_COMPARISON_NEVER,
        {0.0f,0.0f,0.0f,0.0f},
        -FLT_MAX,
        FLT_MAX
    };

    if (FAILED(m_pDevice->CreateSamplerState(&desc, &pState)))
    {
        return NULL;
    }
    
    return new RBShaderSamplerState(pState);
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
RBRasterizerState* RBD3D11HardwareBufferManager::CreateRasterizerState( const RBMaterial& material )
{
    ID3D11RasterizerState* pState;
    D3D11_RASTERIZER_DESC desc = 
    {   
        material.RasterState.IsWireframe ? D3D11_FILL_WIREFRAME : D3D11_FILL_SOLID,
        (material.RasterState.Cull==RBMaterial::MCM_BACK) ? D3D11_CULL_BACK : (material.RasterState.Cull==RBMaterial::MCM_FRONT) ? D3D11_CULL_FRONT : D3D11_CULL_NONE,
        material.RasterState.FrontCounterClockwise,
        D3D11_DEFAULT_DEPTH_BIAS,
        D3D11_DEFAULT_DEPTH_BIAS_CLAMP,
        D3D11_DEFAULT_SLOPE_SCALED_DEPTH_BIAS,
        TRUE,
        FALSE,
        FALSE,
        FALSE
    };

    if (FAILED(m_pDevice->CreateRasterizerState(&desc, &pState)))
    {
        return NULL;
    }
    return new RBRasterizerState(pState);
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
RBBlendState* RBD3D11HardwareBufferManager::CreateBlendState( const RBMaterial& material, uint32 colorWrites )
{
    ID3D11BlendState* pState;

#pragma TODO("Support multiple color write for MRTs")
    D3D11_BLEND_DESC desc;
    desc.AlphaToCoverageEnable = FALSE;
    desc.IndependentBlendEnable = FALSE;
    
    desc.RenderTarget[0].BlendEnable = false;
    desc.RenderTarget[0].SrcBlend = (D3D11_BLEND)material.BlendState.SrcBlend;
    desc.RenderTarget[0].DestBlend = (D3D11_BLEND)material.BlendState.DestBlend;
    desc.RenderTarget[0].BlendOp = (D3D11_BLEND_OP)material.BlendState.BlendOp;
    desc.RenderTarget[0].SrcBlendAlpha = (D3D11_BLEND)material.BlendState.SrcBlendAlpha;
    desc.RenderTarget[0].DestBlendAlpha = (D3D11_BLEND)material.BlendState.DestBlendAlpha;
    desc.RenderTarget[0].BlendOpAlpha = (D3D11_BLEND_OP)material.BlendState.BlendOpAlpha;
    desc.RenderTarget[0].RenderTargetWriteMask = colorWrites & RBRenderer::COLOR_WRITE_ALL;

    if (FAILED(m_pDevice->CreateBlendState(&desc, &pState)))
    {
        return NULL;
    }
    return new RBBlendState(pState);
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
RBDepthStencilState* RBD3D11HardwareBufferManager::CreateDepthStencilState( const RBMaterial& material )
{
    ID3D11DepthStencilState* pState=NULL;
    D3D11_DEPTH_STENCIL_DESC desc =
    {
        material.DepthState.ZEnable,
        material.DepthState.ZWriteEnable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO,
        (D3D11_COMPARISON_FUNC)material.DepthState.ZFunc,
        material.DepthState.StencilEnable,
        material.DepthState.StencilMask,
        material.DepthState.StencilWriteMask,
        {(D3D11_STENCIL_OP)material.DepthState.StencilFrontFaceFailOp, 
         (D3D11_STENCIL_OP)material.DepthState.StencilFrontFaceDepthFailOp, 
         (D3D11_STENCIL_OP)material.DepthState.StencilFrontFacePassOp, 
         (D3D11_COMPARISON_FUNC)material.DepthState.StencilFrontFaceFunc},
        {(D3D11_STENCIL_OP)material.DepthState.StencilBackFaceFailOp, 
        (D3D11_STENCIL_OP)material.DepthState.StencilBackFaceDepthFailOp, 
        (D3D11_STENCIL_OP)material.DepthState.StencilBackFacePassOp, 
        (D3D11_COMPARISON_FUNC)material.DepthState.StencilBackFaceFunc},
    };

    if (FAILED(m_pDevice->CreateDepthStencilState(&desc, &pState)))
    {
        return NULL;
    }

    return new RBDepthStencilState(pState, material.DepthState.StencilRef);
}

bool RBD3D11HardwareBufferManager::create_texture( ID3D11Device* dev, const char* filename, ID3D11ShaderResourceView** ppRV )
{
    D3DX11_IMAGE_INFO img_desc;
    HRESULT hr = D3DX11GetImageInfoFromFileA(filename, NULL, &img_desc, NULL);

    if (FAILED(hr))
    {
        return false;
    }
    

    D3DX11_IMAGE_LOAD_INFO d3dLoadInfo;
    {
        d3dLoadInfo.Width = img_desc.Width;
        d3dLoadInfo.Height = img_desc.Height;
        d3dLoadInfo.Depth = img_desc.Depth;
        d3dLoadInfo.FirstMipLevel = D3DX11_DEFAULT;
        d3dLoadInfo.MipLevels = img_desc.MipLevels;
        d3dLoadInfo.Usage = RBD3D11Mappings::get_d3d_usage(rb_hw_buffer_usage::HBU_DEFAULT);
        d3dLoadInfo.BindFlags = D3DX11_DEFAULT;
        d3dLoadInfo.CpuAccessFlags = 0;
        d3dLoadInfo.MiscFlags = D3DX11_DEFAULT;
        d3dLoadInfo.Format = DXGI_FORMAT_FROM_FILE;
        d3dLoadInfo.Filter = D3DX11_DEFAULT;
        d3dLoadInfo.MipFilter = D3DX11_DEFAULT;
        d3dLoadInfo.pSrcInfo = NULL;

    }

    ID3D11Resource* res;

    hr = D3DX11CreateTextureFromFileA(dev, filename, &d3dLoadInfo, NULL, &res, NULL);
    if (FAILED(hr))
    {
        return false;
    }

    D3D11_RESOURCE_DIMENSION dims;
    res->GetType(&dims);

    CD3D11_SHADER_RESOURCE_VIEW_DESC desc;
    switch (dims)
    {
    case D3D11_RESOURCE_DIMENSION_TEXTURE1D:
        desc = CD3D11_SHADER_RESOURCE_VIEW_DESC((ID3D11Texture1D*)res, D3D11_SRV_DIMENSION_TEXTURE1D);
        break;
    case D3D11_RESOURCE_DIMENSION_TEXTURE2D:
        desc = CD3D11_SHADER_RESOURCE_VIEW_DESC((ID3D11Texture2D*)res, D3D11_SRV_DIMENSION_TEXTURE2D);
        break;
    case D3D11_RESOURCE_DIMENSION_TEXTURE3D:
        desc = CD3D11_SHADER_RESOURCE_VIEW_DESC((ID3D11Texture3D*)res);
        break;
    default:
        return false;
        break;
    }
    

    hr = dev->CreateShaderResourceView(res, &desc, ppRV);

    return SUCCEEDED(hr);
}


/***********************************************************************************************************/
